"""Graphics utilities"""

from pyglet.gl import *
import ctypes


class DisplayList:
	"""Compile drawing commands into an OpenGL display list"""

	name = None
	_compiling = None

	def __init__(self, draw_function=None):
		"""Create a display list.

		draw_function -- an optional callable object. If specified, the
		display list is initialized immediately and the draw_function is
		called compiling drawing commands it issues into the display list.
		After draw_function returns, compiling is ended. This allows you to
		replace this code:

		>>> dl = DisplayList()
		>>> dl.begin()
		>>> draw_stuff()
		>>> dl.end()

		with this single line:

		>>> dl = DisplayList(draw_stuff)

		Note if no draw_function is specified, the OpenGL display list is not
		actually created until the begin() method is class
		"""
		if draw_function is not None:
			self.begin()
			draw_function()
			self.end()

	def begin(self, execute=False):
		"""Begin compiling commands into the display list. If the display list
		has already been compiled, its previously compiled commands are replaced.
		Only one display list may be compiled at a time.

		if execute is True, then the commands are executed immediately as they
		are compiled, otherwise they are only compiled and not executed.
		"""
		assert self._compiling is None, "Already compiling a display list"
		if self.name is None:
			self.name = glGenLists(1)
		if execute:
			mode = GL_COMPILE_AND_EXECUTE
		else:
			mode = GL_COMPILE
		glNewList(self.name, mode)
		DisplayList._compiling = self.name
	
	def end(self):
		"""Stop compiling commands into the display list. Must balance a call to
		the begin() method
		"""
		assert self._compiling == self.name, "This display list is not being compiled"
		glEndList()
		DisplayList._compiling = None
	
	@property
	def is_compiled(self):
		"""Return true if the display list has been compiled and can be executed.
		"""
		return self.name is not None and DisplayList._compiling != self.name
	
	def execute(self):
		"""Execute compiled display list commands"""
		assert self.name is not None, "Display list not compiled"
		glCallList(self.name)
	
	@classmethod
	def execute_many(cls, *display_lists):
		"""Efficiently execute multiple display lists in the order specified"""
		names = (ctypes.c_int * len(display_lists))(*[dl.name for dl in display_lists])
		glCallLists(len(display_lists), GL_INT, names)
	
	def delete(self):
		"""Delete the compiled display list commands. This will happen
		automatically when the object is garbage collected, but you can
		call this manually to force immediate deletion.
		"""
		if self.name is not None and glDeleteLists is not None:
			glDeleteLists(self.name, 1)
			self.name = None
	
	__del__ = delete
